package aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * @author 26029
 * @date 2025/4/15
 * @description
 */
public class LearnJDKProxy {
    public static void main(String[] args) {
        // JDK动态代理
        Subject realSubject = new RealSubject();
        InvocationHandler handler = new InvocationHandlerDemo(realSubject);
        // 创建代理对象
        // Proxy.newProxyInstance()的作用是运行时动态生成一个类
        // 可以用接口Subject接收,因为动态代理类实现了Subject的接口
        Subject subject = (Subject) Proxy.newProxyInstance(
                Subject.class.getClassLoader(), // 类加载器:这个代理类要实现Subject的接口，当然使用Subject的类加载器
                realSubject.getClass().getInterfaces(), // 代理类实现的接口
                handler // 所有方法调用转发给handler.invoke()
        );
        subject.hello("World");
        String result = subject.bye();
        System.out.println(result);

        Class<?> clazz = subject.getClass();
        System.out.println("代理类的方法:");
        Method[] clazz_methods = clazz.getDeclaredMethods();
        for (Method method : clazz_methods)
            System.out.println(method.getName());
        System.out.println("代理类的名字:" + clazz.getName());
        System.out.println("代理类的接口:" + Arrays.toString(clazz.getInterfaces()));
    }
}

class InvocationHandlerDemo implements InvocationHandler {
    // 要代理的真实对象
    private Object subject;

    public InvocationHandlerDemo(Object object) {
        this.subject = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在代理真实对象前我们可以添加一些自己的操作
        System.out.println("在代理真实对象之前的操作...");
        // 调用真实代理对象的方法,这一步通过反射调用了真实对象RealSubject的方法
        Object obj = method.invoke(subject, args);
        // 在代理真实对象后我们可以添加一些自己的操作
        System.out.println("在代理真实对象之后的操作...");
        return obj;
    }
}

class RealSubject implements Subject {

    @Override
    public void hello(String str) {
        System.out.println("Hello " + str);
    }

    @Override
    public String bye() {
        System.out.println("Good Bye");
        return "Over";
    }
}

interface Subject {

    void hello(String str);

    String bye();
}